Skip to content

Review Project 4 semantic check implementation - #4

Draft
wuzhi456 with Copilot wants to merge 3 commits into
my-project4from
copilot/check-semantic-errors
Draft

Review Project 4 semantic check implementation#4
wuzhi456 with Copilot wants to merge 3 commits into
my-project4from
copilot/check-semantic-errors

Conversation

Copilot AI commented Nov 29, 2025

Copy link
Copy Markdown
  • Explore repository structure and understand Project 4 requirements
  • Build and run existing tests to understand current state
  • Review semantic error handling against Project 4 requirements:
    • Check type equality rules (2.1) - PASS
    • Check expression semantics and constraints (2.2) - PASS
    • Check 0 as null pointer handling (2.3) - PASS
    • Check statement semantics (2.4) - PASS
    • Check error reporting templates (3.2) - PASS
    • Check struct tag scope (v3 errata Section 5) - PASS
  • Verify base_01 test passes - PASS
  • Run code review - No issues found
  • Run CodeQL security check - No vulnerabilities found

Responding to User Comment

Tested equality comparison (==, !=) for struct and pointer types. All scenarios work correctly:

  1. struct a* == struct a* - works (both pointers)
  2. struct a* == struct b* - errors (different pointer types)
  3. struct a == struct a - errors (struct is not int/pointer per [2.2.12])
  4. int* == struct a* - errors (different pointer types)

Asked user for clarification on what specific case is failing.

Original prompt

帮我看看现在的代码有没有什么不符合项目要求的地方,尤其是检查语义报错相关的地方(即本次项目主要的内容),以下是项目要求:Project 4 - Semantic Check Part 2 (Rev. v4)
2025 年 11 月 27 日
我们于 Nov 24 发布了 v2 版本的文档,对“3.2 预定义的语义错误模板”中常见问题进行了回答。
我们于 Nov 26 发布了 v3 版本的文档,对 Project 3 中一处文档错误进行修订,该错误会影响到本次
Project 的内容,请阅读第 5 章并修改你在 Project 3 中的实现代码。
我们于 Nov 27 发布了 v4 版本的文档,对文档中潜在的歧义和未清晰说明的地方进行了补充, 请仔细阅
读红色高亮部分。
1 项目要求
在 Project 3 中,你已经完成了符号表和对类型的表示。在 Project 4 中,你需要基于上述类型系统和符号
表完成语义分析中的类型检查。
1.1 项目假设
在 Project 4 中,我们继承来自 Project 3 的如下假设:
• 样例可能存在语义错误,但不存在 Project 3 中规定的语义错误;
• specifier 中的完整结构体规则出现时,它在语法树中一定是全局变量定义或全局结构体声明的任意次
子节点,即它不会出现在函数参数(包含函数声明和函数定义)、函数体内;
并新增如下假设:
• specifier 不再能够被推导为 CHAR,即 char 类型不再会出现;同时,字符常量 Char 也不会出现。
• 样例中出现的结构体均是被完整声明过的,即不存在 incomplete structure。
• 函数声明与 函数定义一定相符,即函数的返回类型与参数列表一定相同,你不需要进行额外检查。
• 函数的返回类型只能为 int。
1.2 扩展要求
扩展部分在每个 Project 之间都是独立计分的,在后续的 Project 中移除对某扩展部分的支持不影响前
序 Project 的分数。也就是说,你可以选择在前面的 Project 中完成较为简单的扩展任务;如果你发现
在后续的 Project 中完成扩展部分过于困难,你可以选择不完成后续 Project 的扩展部分,这样不会影
响你前面 Project 的分数。
本项目的扩展部分与前序 Project 保持一致,你需要确保你的类型检查能够正确处理结构体和指针相关的
语法。
1
2 类型检查
2.1 类型相等
对于两个类型,它们被视为相等/相同,若它们均是:
• int;
• array,并且它们的 element type 相等。
• structure,并且它们是同一个结构体类型。
• pointer,并且它们的 reference type 相等。
2.2 expression 的语义与约束
每个 expression 具有两种属性:类型和值分类(Value Category, (表格中简写为 VC), lvalue 或 rvalue);
并且,我们对于其 operand 也有要求。
Rule Return Type VC Constr.
标识符 数字常量 括号 函数调用 数组访问 结构体访问 结构体指针访问 取地址 解引用 后缀自增、后缀自减、前缀自增、前缀自减 加法、减法 一元正号、一元负号、乘法、除法、取模 大于等于、大于、小于、小于等于 等于、不等 逻辑非、逻辑或、逻辑与 赋值 与其声明一致 int 与内部 expression 一致 函数返回类型 T(见下) 该结构体成员的类型 该结构体成员的类型 T →pointer to T pointer to T →T 与 Operand 一致(整型或指针) 见下 整型 整型 整型 整型 与右侧 Operand 一致 lvalue rvalue
与内部一致
rvalue lvalue lvalue lvalue rvalue lvalue rvalue rvalue rvalue rvalue rvalue rvalue rvalue [2.2.1]
[2.2.2]
[2.2.3]
[2.2.4]
[2.2.5]
[2.2.6]
[2.2.7]
[2.2.8]
[2.2.9]
[2.2.10]
[2.2.11]
[2.2.12]
[2.2.13]
[2.2.14]
• [2.2.1] Identifier 所引用的是一个 object (变量),而不是函数。
• [2.2.2] Identifier 所引用的应是一个函数(可以被声明但是未被定义过),参数的类型应该与其声明一致。
• [2.2.3] 数组访问:第一个 Operand 的类型应为 array of T 或者 pointer to T,若类型为 array,则要求它
为 lvalue,第二个 Operand 应该为整型。
• [2.2.4] 结构体访问:第一个 Operand 的类型应为 complete structure type,并且为 lvalue,Identifier 应是
该结构体的成员。
2
• [2.2.5] 结构体指针访问:第一个 Operand 的类型应为 pointer to complete structure type,Identifier 应是
该结构体的成员。
• [2.2.6] 取地址:Operand 应为一个 lvalue。
• [2.2.7] 解引用:Operand 应为一个指针类型。
• [2.2.8] 自增、自减:Operand 应是整型或指针,以及是一个 lvalue。指针对整数的加减法的语义见下。
• [2.2.9] 加减法:若 加法、减法 两侧的 Operand 均为整型,则其结果为整型。v4 修改:
− 对于加法:若其一侧 Operand 为指针,另一侧 Operand 为整型,则结果为指针 Operand 的类型,其
语义为该指针后第 n 个元素的地址。
− 对于减法:若其左侧 Operand 为指针,右侧 Operand 为整型,则结果为指针 Operand 的类型,其
语义为该指针前第 n 个元素的地址。p - n 的语义与 p + (-n) 的语义一致。
− 对于减法:若其左侧 Operand 为整型,右侧 Operand 为指针,该情况为语义错误。
− 对于减法:若两侧均为同类型指针,则结果为整型,其语义为两个指针之间相差多少个该类型的对象。
− 否则,是语义错误。
• [2.2.10] 算数运算:Operand 应是整型。
• [2.2.11] 比较:Operand 应是整型。
• [2.2.12] 相等比较:Operand 应是整型或指针,并且两个 Operand 类型相同。
• [2.2.13] 逻辑运算:Operand 应是整型或指针。指针在逻辑运算中的语义为与 0 比较,非 0 则为真。
• [2.2.14] 赋值: Operand 应是整型或指针,并且两个 Operand 类型相同。左侧 Operand 应该是 lvalue。该
表达式的返回值为右侧 Operand 的值。
2.3 0 与 null
在某些条件下,数字常量 0 可以被视为一个指针,它代表空指针。
在我们的 Project 中,上述条件被限制为:直接1出现在赋值的右侧,或者在相等比较的两侧。
示例 1
int main() {
int *p;
p = 0; // OK
p = 20; // Error
}
2.4 statement 的语义和约束
• 局部变量定义:若 ASSIGN expression 子句存在,v4 修改:使用 [2.2.14] 规则2对此处的 expression
与变量的定义类型进行检查。
• 返回语句:返回值的类型应该与函数定义中的返回类型一致。
• If 语句与 While 语句:其中 expression 的类型要求为整型或指针。
3
1 指该 expression 被推导为嵌套 0 个或多个括号的数字常量 0,而不能经过其他任何 expression 产生式。
2 v4 新增:同样的,若类型不符,使用 unmatchedTypeForBinaryOP 而不是 unexpectedType 来汇报错误。
3 Project 4 语义检查实现
初始代码位于 https://github.com/sqlab-sustech/CS323-Compilers-2025F-Projects
的 project4-base 分支。请参照 Project Zero,在你 Project 3 代码基础上合并来自 project4-base 分支的
代码。
你需要完成 impl.Compiler 类,基础代码已经给出,注意不要绕过 Grader 打印内容。
若你需要修改 framework 包下的文件,请确保你的程序行为不依赖于你所修改的部分。在测评时,
framework 包下所有文件均会被删除,然后替换为我们提供的版本。
3.1 报告语义错误
每个样例文件中可能存在零个、一个或多个语义错误。但是,每个 statemennt SubRule 下,至多存在一
个语义错误。
你需要遍历所有 statemennt,并对其中每个 expression 按照要求进行语义检查,汇报遇到的语义错误。
当你遇到一个语义错误时,你可以停止对整个 expression 树的剩余处理。
即你不需要考虑如何进行错误恢复,遇到错误时直接停止整个 expression 的检查,然后开始下一个
statemennt 的检查即可。
与 Project 3 类似,所有错误报告函数均已预定义在 framework.project4.Project4SemanticError 下。
额外的,我们预定义了一种异常 Project4Exception,你可以在内部处理 expression 遇到语义错误时抛出它,
在遍历 statement 处捕获它并向 Grader 汇报,然后开始处理下一个 statemennt。
Project 4 核心逻辑示例
public class ExprVisitor extends SplcBaseVisitor {
@OverRide
public Void visitExprID(SplcParser.ExprIDContext ctx) {
String id = ctx.Identifier().getText();
// ...
Project4SemanticError.identifierNotVariable(ctx, id).throwException();
// ...
}
}
// in Your Compiler class:
new SplcBaseVisitor() {
@OverRide
public Void visitStmtExpr(SplcParser.StmtExprContext ctx) {
try {
new ExprVisitor().visit(ctx.expression());
} catch (Project4Exception ex) {
grader.reportSemanticError(ex);
}
return null;
}
}.visit(programContext);
4
3.2 预定义的语义错误模板
Project4SemanticError 中定义了如下语义错误的模板:
• identifierNotVariable、identifierNotFunction:当我们期望一个 Identifier 表示变量或函数时,但
是它不是。3
• unexpectedType:Operator 要求 Operand(s) 是特定的类型,但给定的类型不符合文档要求。例如:
− 结构体访问左侧是一个 array type.
− v4 删除:加减法左侧/右侧是一个 array type. 加减法 [2.2.9]、相...


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 2 commits November 29, 2025 01:30
Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>
…lt test file

Co-authored-by: wuzhi456 <217564920+wuzhi456@users.noreply.github.com>
Copilot AI changed the title [WIP] Review code for alignment with project requirements Review Project 4 semantic check implementation Nov 29, 2025
Copilot AI requested a review from wuzhi456 November 29, 2025 01:42
@wuzhi456

wuzhi456 commented Dec 1, 2025

Copy link
Copy Markdown
Owner

@copilot // Equality: ==, !=
if (ctx.EQ() != null || ctx.NEQ() != null) {
Token op = ctx.EQ() != null ? ctx.EQ().getSymbol() : ctx.NEQ().getSymbol();

                // Check if both are integers or pointers
                if (!isIntegerType(lhs.type) && !isPointerType(lhs.type)) {

// Project4SemanticError.unexpectedType(ctx, lhs.type).throwException();
Project4SemanticError.unmatchedTypeForBinaryOP(ctx, op, lhs.type, rhs.type).throwException();
}
// if (!isIntegerType(rhs.type) && !isPointerType(rhs.type)) {
// Project4SemanticError.unexpectedType(ctx, rhs.type).throwException();
// }

                // Special case: allow 0 as null pointer
                boolean lhsIsZero = isConstantZero(ctx.expression(0));
                boolean rhsIsZero = isConstantZero(ctx.expression(1));

                if (!lhsIsZero && !rhsIsZero && !typesEqual(lhs.type, rhs.type)) {
                    Project4SemanticError.unmatchedTypeForBinaryOP(ctx, op, lhs.type, rhs.type).throwException();
                }

                return new ExprInfo(new BasicType(BasicType.Kind.INT), false);
            }问题在这里,项目要求2.1 类型相等

对于两个类型,它们被视为相等/相同,若它们均是:
• int;
• array,并且它们的 element type 相等,(v5)以及它们的数组长度相等。
• structure,并且它们是同一个结构体类型。
• pointer,并且它们的 reference type 相等。但是现在无法比较structrue和 pointer

Copilot AI commented Dec 1, 2025

Copy link
Copy Markdown
Author

@copilot // Equality: ==, !=
if (ctx.EQ() != null || ctx.NEQ() != null) {
Token op = ctx.EQ() != null ? ctx.EQ().getSymbol() : ctx.NEQ().getSymbol();...

Could you clarify what specific case is failing? I tested the following scenarios and they all behave correctly according to [2.2.12] (which requires operands to be integer or pointer types):

  1. struct a* == struct a* - works correctly (both are pointers)
  2. struct a* == struct b* - correctly errors (different pointer types)
  3. struct a == struct a - correctly errors (struct is not int/pointer)
  4. int* == struct a* - correctly errors (different pointer types)

The typesEqual function correctly compares PointerType instances by checking their referenced types, which includes StructType comparison via tag name.

Are you seeing a specific error that shouldn't occur, or is a comparison being accepted that should be rejected?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants